package application

import (
	"fmt"
	"gowin32/pkg"
	"gowin32/types"
	"syscall"
	"time"
	"unsafe"
)

const (
	ComputerNamePhysicalNetBIOS     = 0
	ComputerNamePhysicalDnsHostname = 1
	ComputerNamePhysicalDnsDomain   = 2
	ComputerNameDnsHostname         = 3
	ComputerNameDnsDomain           = 4
	ComputerNameDnsFullyQualified   = 5
	ComputerNameMax                 = 6
)

type SystemTime struct {
	Year         types.WORD
	Month        types.WORD
	DayOfWeek    types.WORD
	Day          types.WORD
	Hour         types.WORD
	Minute       types.WORD
	Second       types.WORD
	Milliseconds types.WORD
}

var (
	procGetLocalTime                       = pkg.ModKernel32.NewProc("GetLocalTime")
	procSetLocalTime                       = pkg.ModKernel32.NewProc("SetLocalTime")
	procGetComputerNameExA                 = pkg.ModKernel32.NewProc("GetComputerNameExA")
	procGetSystemInfo                      = pkg.ModKernel32.NewProc("GetSystemInfo")
	procGetPhysicallyInstalledSystemMemory = pkg.ModKernel32.NewProc("GetPhysicallyInstalledSystemMemory")
)

func GetLocalTime() (time.Time, error) {
	var st SystemTime
	procGetLocalTime.Call(uintptr(unsafe.Pointer(&st)))
	localTime := time.Date(int(st.Year), time.Month(st.Month), int(st.Day), int(st.Hour), int(st.Minute), int(st.Second), int(st.Milliseconds)*int(time.Millisecond), time.Local)
	return localTime, nil
}

func SetLocalTime(t time.Time) {
	var st SystemTime
	st = SystemTime{
		Year:         types.WORD(t.Year()),
		Month:        types.WORD(t.Month()),
		DayOfWeek:    types.WORD(t.Weekday()),
		Day:          types.WORD(t.Day()),
		Hour:         types.WORD(t.Hour()),
		Minute:       types.WORD(t.Minute()),
		Second:       types.WORD(t.Second()),
		Milliseconds: types.WORD(t.Nanosecond() / 1000000),
	}
	procSetLocalTime.Call(uintptr(unsafe.Pointer(&st)))
}

func GetComputerNameExA() (string, error) {
	var buf [4096]uint16
	nSize := uint32(len(buf))
	r1, _, _ := procGetComputerNameExA.Call(ComputerNamePhysicalNetBIOS, uintptr(unsafe.Pointer(&buf)), uintptr(nSize))
	if r1 != 0 {
		fmt.Println(syscall.GetLastError())
	}
	name := syscall.UTF16ToString(buf[:])
	return name, nil
}

func GetComputerNameExW() {
	var buf [4096]uint16
	nSize := uint32(len(buf))
	syscall.GetComputerName(&buf[0], &nSize)
	fmt.Println(buf)

}

type SystemInfo struct {
	ProcessorArchitecture     types.WORD
	Reserved                  types.WORD
	PageSize                  types.DWORD
	MinimumApplicationAddress uintptr
	MaximumApplicationAddress uintptr
	ActiveProcessorMask       uintptr
	NumberOfProcessors        types.DWORD
	ProcessorType             types.DWORD
	AllocationGranularity     types.DWORD
	ProcessorLevel            types.WORD
	ProcessorRevision         types.WORD
}

func GetSystemInfo() SystemInfo {
	var sysInfo SystemInfo
	procGetSystemInfo.Call(uintptr(unsafe.Pointer(&sysInfo)))
	return sysInfo
}

// GetPhysicallyInstalledSystemMemory return the system arm by MB
func GetPhysicallyInstalledSystemMemory() uint64 {
	var size types.PULONGLONG
	procGetPhysicallyInstalledSystemMemory.Call(uintptr(unsafe.Pointer(&size)))
	return uint64(size / 1024)
}
